package top.onedream.buildsmallsoftware.util

import com.fasterxml.jackson.databind.ObjectMapper
import io.jsonwebtoken.Claims
import io.jsonwebtoken.JwtBuilder
import io.jsonwebtoken.Jwts
import io.jsonwebtoken.SignatureAlgorithm
import top.onedream.buildsmallsoftware.model.user.User
import java.util.*

/**
 * jwt工具类 生成、解析、校验token
 */
object JwtUtil {


    /**
     * 用户登录成功后生成jwt
     * 使用Hs256算法
     * 三部分组成 头部+荷载+签证信息
     * @param ttlMillis jwt过期时间
     * @param user      登录成功的user对象
     * @return
     */
    fun createJwt(user: User, signingKey: String): String {
        // header部分，jwt已经封装好了
        val signatureAlgorithm: SignatureAlgorithm = SignatureAlgorithm.HS256

        // jwt生成时间 当前时间
        val nowMillis = System.currentTimeMillis()
        val date = Date(nowMillis)

        // payload 荷载部分（存放有效信息的地方，包含标准中注册的声明、公共声明、私有声明）
        // 创建私有声明
        val claims: MutableMap<String, Any> = HashMap()
        claims["user"] = ObjectMapper().writeValueAsString(user)

        // 生成秘钥secret用
//        String key = user.getUserPassword();
        val bytes: ByteArray = signingKey.toByteArray()
        // 生成签发人
        val subject: String = user.username!!

        // 为payload添加标准声明和私有声明（new一个JwtBuilder，设置jwt的body）
        val jwtBuilder: JwtBuilder = Jwts.builder() // 先设置自己创建的私有声明，要是写在标准声明后面，会覆盖掉标准声明
            .setClaims(claims) // 设置jti（jwt id），主要用来作为一次性token，从而回避重放攻击
//            .setId(UUID.randomUUID().toString()) // 设置iat jwt签发时间
            .setSubject(subject) // 设置签名使用的签名算法和签名使用的秘钥
            .signWith(signatureAlgorithm, bytes)
        return  jwtBuilder.compact()
    }

    /**
     * 解密jwt
     * 解析jwt
     * @param [token] 需要被解密的token
     * @return [Claims]
     */
    fun parseJWT(token: String?, signingKey: String): Claims {
        // 签名秘钥（与生成签名的秘钥一样）
        val key: ByteArray = signingKey.toByteArray()

        // 得到DefaultJwtParser
        return Jwts.parser() // 设置签名的秘钥
            .setSigningKey(key) // 设置需要解析的jwt
            .parseClaimsJws(token)
            .body
    }

}
